/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Armin Lunkeit, Fabian Poehland, Leonard Scharff
 *
 * This implementation is part of the Java Program Simplex129 
 *
 * Permission is hereby granted, free of charge, to any person obtaining _a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package tub.adm1;

import java.io.File;
import java.util.Vector;

/**
 * @author _a.lunkeit - alunkeit(at)gmail(dot)com
 * 
 */
public class Main
{

  /**
   * 
   */
  public Main()
  {
    // TODO Auto-generated constructor stub
  }

  /**
   * A special implementation to find out something about the runtime behavior
   * of the algorithms.
   * 
   * V5C.cat maximal flow from vertex 1 to vertex 5 : 12.0 maximal flow from
   * vertex 3 to vertex 5 : 10.0
   * 
   * V5CD.cat maximal flow from vertex 1 to vertex 5 : 11.0 maximal flow from
   * vertex 3 to vertex 5 : 2.0
   * 
   * 
   * V200E800.cat maximal flow from vertex 1 to vertex 200 : 11.194676 maximal
   * flow from vertex 12 to vertex 56 : 15.641528 maximal flow from vertex 79 to
   * vertex 187 : 10.117965 maximal flow from vertex 150 to vertex 50 :
   * 17.823764 V200E800D.cat maximal flow from vertex 1 to vertex 200 : 5.230433
   * maximal flow from vertex 12 to vertex 56 : 9.212543 maximal flow from
   * vertex 79 to vertex 187 : 8.151562 maximal flow from vertex 150 to vertex
   * 50 : 8.78751
   * 
   * Grid50x50.cat maximal flow from vertex 1 to vertex 2500 : 0.959804 maximal
   * flow from vertex 1 to vertex 1111 : 0.959804 maximal flow from vertex 2 to
   * vertex 2500 : 5.760347 maximal flow from vertex 2 to vertex 50 : 10.234722
   * maximal flow from vertex 234 to vertex 2179 : 15.558781
   * 
   * Grid50x50D.cat maximal flow from vertex 1 to vertex 2500 : 0.959804 maximal
   * flow from vertex 1 to vertex 2500 : 0.959804 maximal flow from vertex 2 to
   * vertex 2500 : 5.760347 maximal flow from vertex 2 to vertex 50 : 0.460373
   * maximal flow from vertex 234 to vertex 2179 : 0
   * 
   * V406E607.cat maximal flow from vertex 1 to vertex 2 : 203.0 maximal flow
   * from vertex 1 to vertex 406 : 101.0
   * 
   * V20006E30007.cat maximal flow from vertex 1 to vertex 20006 : 5001.0
   * maximal flow from vertex 1 to vertex 2 : 10003.0
   */

  static class Operation
  {
    String _file;

    String _algo;

    int _s;

    int _t;

    float _ekflow;
    
    float _gtflow;

    long _ekVal;

    long _gtVal;
  }

  protected static Operation makeOperation( String file, int s, int t )
  {
    Operation o = new Operation();

    o._file = file;
    o._s = s;
    o._t = t;

    return o;
  }

  protected static void runStatistics()
  {
    File f = new File( System.getProperty( "user.dir" ) + "/cat/maxflows/" );

    Vector<Operation> operations = new Vector<Operation>();

    operations.add( makeOperation( f.toString() + "/V5C.cat", 1, 5 ) );
    operations.add( makeOperation( f.toString() + "/V5C.cat", 3, 5 ) );

    operations.add( makeOperation( f.toString() + "/V5CD.cat", 1, 5 ) );
    operations.add( makeOperation( f.toString() + "/V5CD.cat", 3, 5 ) );

    operations.add( makeOperation( f.toString() + "/V200E800.cat", 1, 200 ) );
    operations.add( makeOperation( f.toString() + "/V200E800.cat", 12, 56 ) );
    operations.add( makeOperation( f.toString() + "/V200E800.cat", 79, 187 ) );
    operations.add( makeOperation( f.toString() + "/V200E800.cat", 150, 50 ) );

    operations.add( makeOperation( f.toString() + "/V200E800D.cat", 1, 200 ) );
    operations.add( makeOperation( f.toString() + "/V200E800D.cat", 12, 56 ) );
    operations.add( makeOperation( f.toString() + "/V200E800D.cat", 79, 187 ) );
    operations.add( makeOperation( f.toString() + "/V200E800D.cat", 150, 50 ) );

    // Heap space error
    //operations.add( makeOperation( f.toString() + "/V20006E30007.cat", 1, 20006 ) );
    //operations.add( makeOperation( f.toString() + "/V20006E30007.cat", 1, 2 ) );

    /**
     * Grid50x50.cat maximal flow from vertex 1 to vertex 2500 : 0.959804
     * maximal flow from vertex 1 to vertex 1111 : 0.959804 maximal flow from
     * vertex 2 to vertex 2500 : 5.760347 maximal flow from vertex 2 to vertex
     * 50 : 10.234722 maximal flow from vertex 234 to vertex 2179 : 15.558781
     */

    operations.add( makeOperation( f.toString() + "/Grid50x50.cat", 1, 2500 ) );
    operations.add( makeOperation( f.toString() + "/Grid50x50.cat", 1, 1111 ) );
    operations.add( makeOperation( f.toString() + "/Grid50x50.cat", 2, 2500 ) );
    operations.add( makeOperation( f.toString() + "/Grid50x50.cat", 2, 50 ) );
    operations.add( makeOperation( f.toString() + "/Grid50x50.cat", 234, 2179 ) );

    /**
     * Grid50x50D.cat maximal flow from vertex 1 to vertex 2500 : 0.959804
     * maximal flow from vertex 1 to vertex 2500 : 0.959804 maximal flow from
     * vertex 2 to vertex 2500 : 5.760347 maximal flow from vertex 2 to vertex
     * 50 : 0.460373 maximal flow from vertex 234 to vertex 2179 : 0
     */

    operations.add( makeOperation( f.toString() + "/Grid50x50D.cat", 1, 2500 ) );
    operations.add( makeOperation( f.toString() + "/Grid50x50D.cat", 2, 2500 ) );
    operations.add( makeOperation( f.toString() + "/Grid50x50D.cat", 2, 50 ) );
    operations.add( makeOperation( f.toString() + "/Grid50x50D.cat", 234, 2179 ) );

    operations.add( makeOperation( f.toString() + "/V406E607.cat", 1, 2 ));
    operations.add( makeOperation( f.toString() + "/V406E607.cat", 1, 406 ));

    
    for( Operation o : operations )
    {
      o._ekVal = runEK( o );
      o._gtVal = runGT( o );
    }
    
    System.out.println( "--------------------------------------------------------------------------------------------------------------" );
    System.out.format( "%-16s\t %-16s%-16s%-16s%-16s%-16s\n","File","Flow(EK)","Flow(GT)","EK (ms)","GT(ms)","GT - EK(ms)" );
    System.out.println( "--------------------------------------------------------------------------------------------------------------" );

    for( Operation o : operations )
    {
      long percent = o._gtVal - o._ekVal;

      try
      {
        String file = o._file.substring( o._file.length() - 16,
            o._file.length() );
        
        System.out.format( "%16s\t %.6f\t %.6f\t %-16d %-16d %-16d\n", file, o._ekflow, o._gtflow,
            o._ekVal, o._gtVal, percent );
      }
      catch( Exception e )
      {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }

  protected static long runEK( Operation o )
  {
    try
    {
      Graph g = new Graph();

      g.init( o._file );

      long start = System.currentTimeMillis();

      System.out.println( "------------------------------------------------------" );
      System.out.println( "start EdmondsKarp with " + o._file + "(s) := "
          + o._s + " t := " + o._t );

      EdmondsKarp ek = new EdmondsKarp( g );
      o._ekflow = ek.solve( o._s, o._t );

      long end = System.currentTimeMillis();
      
      System.out.println( "ek finished: " + o._file );
      System.out.println( "Flow result: " + o._ekflow );
      System.out.println( "Required time: " + (end - start) + " ms");
      System.out.println( "------------------------------------------------------" );

      return end - start;
    }
    catch( Exception e )
    {
      e.printStackTrace();

      return -1;
    }
  }

  protected static long runGT( Operation o )
  {
    try
    {
      Graph g = new Graph();

      g.init( o._file );

      long start = System.currentTimeMillis();

      System.out.println( "------------------------------------------------------" );
      System.out.println( "start GoldbergTarjan with " + o._file + "(s) := "
          + o._s + " t := " + o._t );

      GoldbergTarjan gt = new GoldbergTarjan( g );
      o._gtflow = gt.solve( o._s, o._t );
      
      long end = System.currentTimeMillis();
      
      System.out.println( "gt finished: " + o._file );
      System.out.println( "Flow result: " + o._gtflow );
      System.out.println( "Required time: " + (end - start) + " ms");
      System.out.println( "------------------------------------------------------" );

      return end - start;
    }
    catch( Exception e )
    {
      e.printStackTrace();

      return -1;
    }
  }

  /**
   * @param args
   */
  public static void main( String[] args )
  {
    if( args.length == 1 && args[0].equals( "stat" ) )
    {
      runStatistics();
      return;
    }

    if( args.length != 4 )
    {
      System.out.println( "usage: Main s t file algorithm" );
      System.out.println( "Example: java tub/adm1/Main 1 5 VC5.cat ek" );
      System.out
          .println( "\t Explanation for algorithms:\n \t\t ek = EdmondsKarp\n \t\t gt = GoldbergTarjan\n \t\t cmp = compare both" );
    }
    else
    {
      try
      {
        String s = args[0];
        String t = args[1];
        String f = args[2];
        String a = args[3];

        Operation o = new Operation();
        o._s = Integer.parseInt( s );
        o._t = Integer.parseInt( t );
        o._file = f;

        if( a.equalsIgnoreCase( "ek" ) )
        {
          runEK( o );
        }
        else if( a.equalsIgnoreCase( "gt" ) )
        {
          runGT( o );
        }
        else if( a.equalsIgnoreCase( "cmp" ) )
        {
          runEK( o );

          runGT( o );
        }
        else
        {
          System.out
              .println( "Didn't understand algorithm, select a valid one!" );
        }
      }
      catch( Exception e )
      {
        e.printStackTrace();
      }
    }
  }

}
